/*
 *  render.cpp
 *  BioBreak
 *
 *  Created by terry franguiadakis on 2/19/09.
 *  Copyright 2009 __MyCompanyName__. All rights reserved.
 *
 */

#include <math.h>
#include "render.h"


#include <OpenGLES/ES1/gl.h>
#include <OpenGLES/ES1/glext.h>

// -----------------------------------------------------------------------------


void Renderer::SetAlphaFunc(EAlphaFunc i_alphaFunc, float i_threshold)
{
    static EAlphaFunc s_currentAlphaFunc = ENone;
    static float s_threshold = 0.0f;
    if (s_currentAlphaFunc == i_alphaFunc && s_threshold == i_threshold)
        return;
    
    s_currentAlphaFunc = i_alphaFunc;
    s_threshold = i_threshold;
    
    switch (i_alphaFunc) {
        case EBarrier:
            glEnable(GL_ALPHA_TEST);
            glAlphaFunc(GL_GREATER, i_threshold);
            break;
        case EFull:
            glEnable(GL_ALPHA_TEST);
            glAlphaFunc(GL_ALWAYS, 0.0f);
            break;
        case ENone:
            glDisable(GL_ALPHA_TEST);
            break;
        default:
            break;
    }
}

// -----------------------------------------------------------------------------

void BasicDrawObjects::DrawPolygon(const  Vector2f* i_vertices, int i_vertexCount, const Color3f& i_color)
{
   
    glColor4f(i_color.r, i_color.g, i_color.b, 1.0f);
    glVertexPointer(2, GL_FLOAT, 0, i_vertices);
	glEnableClientState(GL_VERTEX_ARRAY);
	
	glDrawArrays(GL_LINE_LOOP, 0, i_vertexCount);
	
	glDisableClientState(GL_VERTEX_ARRAY);  
}


void BasicDrawObjects::DrawTexturedPolygon(const  Vector2f* i_vertices, const Vector2f* i_texCoords, int i_vertexCount, const Color4f i_color)
{
    glEnable(GL_BLEND);
	glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    glColor4f(i_color.r, i_color.g, i_color.b, i_color.a);
    glVertexPointer(2, GL_FLOAT, 0, i_vertices);
    glTexCoordPointer(2, GL_FLOAT, 0, i_texCoords);
	glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    
	glEnableClientState(GL_VERTEX_ARRAY);
	
	glDrawArrays(GL_TRIANGLE_FAN, 0, i_vertexCount);
	
	glDisableClientState(GL_VERTEX_ARRAY);    
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glDisable(GL_BLEND);
}

void BasicDrawObjects::DrawSolidPolygon(const Vector2f* vertices, int i_vertexCount, const Color3f& color)
{
    glEnable(GL_BLEND);
	glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glColor4f(0.5f * color.r, 0.5f * color.g, 0.5f * color.b, 0.5f);
    glVertexPointer(2, GL_FLOAT, 0, vertices);
	
    glEnableClientState(GL_VERTEX_ARRAY);
	
	glDrawArrays(GL_TRIANGLE_FAN, 0, i_vertexCount);
	
	glDisable(GL_BLEND);
    
    glColor4f(color.r, color.g, color.b, 1.0f);
    glDrawArrays(GL_LINE_LOOP, 0, i_vertexCount);	
    
    glDisableClientState(GL_VERTEX_ARRAY);
}

static void drawCircle(const Vector2f& i_center, float i_radius, GLenum i_style)
{
    const unsigned int k_segments = 16.0f;
	const float k_increment = 2.0f * M_PI / float(k_segments);
    static float vertices[(k_segments*2)+2];
    
	float theta = 0.0f;
	
    int vertCnt = 0;
    for (int i = 0; i < k_segments; ++i, vertCnt+=2)
    {
        Vector2f v = i_center +  Vector2f(cosf(theta), sinf(theta)) * i_radius;
        vertices[vertCnt]   = v.x;
        vertices[vertCnt+1] = v.y;
        theta += k_increment;
    }
    
    // draw
    glVertexPointer(2, GL_FLOAT, 0, vertices);
    glEnableClientState(GL_VERTEX_ARRAY);
    glDrawArrays(i_style, 0, (int)k_segments);	
    glDisableClientState(GL_VERTEX_ARRAY);
}


static void drawUnitCircle(GLenum i_style)
{
    const unsigned int k_segments = 16.0f;
	const float k_increment = 2.0f * M_PI / float(k_segments);
    static float vertices[(k_segments*2)+2];
    static bool isUnitCircleCalculated = false;
    
    if (!isUnitCircleCalculated)
    {
        float theta = 0.0f;
        int vertCnt = 0;
        for (int i = 0; i < k_segments; ++i, vertCnt+=2)
        {
            Vector2f v = Vector2f(cosf(theta), sinf(theta));
            vertices[vertCnt]   = v.x;
            vertices[vertCnt+1] = v.y;
            theta += k_increment;
        }
        
    //    isUnitCircleCalculated = true;
    }
    
    // draw
    glVertexPointer(2, GL_FLOAT, 0, vertices);
    glEnableClientState(GL_VERTEX_ARRAY);
    glDrawArrays(i_style, 0, (int)k_segments);	
    glDisableClientState(GL_VERTEX_ARRAY);
}


void BasicDrawObjects::DrawCircle(const Vector2f& i_center, float i_radius, const Color4f& i_color)
{
    glColor4f(i_color.r, i_color.g, i_color.b, i_color.a);
	drawCircle(i_center, i_radius, GL_LINE_LOOP);
    
}

void BasicDrawObjects::DrawSolidCircle(const Vector2f& i_center, float i_radius, const Vector2f& axis, const Color4f& color)
{
    glEnable(GL_BLEND);
	glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glColor4f(color.r, color.g, color.b, color.a);
	drawCircle(i_center, i_radius, GL_TRIANGLE_FAN);
	glDisable(GL_BLEND);
    
	glColor4f(color.r, color.g, color.b, 1.0f);
	drawCircle(i_center, i_radius, GL_LINE_LOOP);
}

void BasicDrawObjects::DrawUnitCircle(const Color3f& i_color)
{
    glColor4f(i_color.r, i_color.g, i_color.b, 1.0f);
	drawUnitCircle(GL_LINE_LOOP);
}

void BasicDrawObjects::DrawSolidUnitCircle(const Color3f& color)
{
 //   glEnable(GL_BLEND);
//	glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glColor4f(0.5f * color.r, 0.5f * color.g, 0.5f * color.b, 1.0f); // BB (TEF) don't check in.
	drawUnitCircle(GL_TRIANGLE_FAN);
//	glDisable(GL_BLEND);
    
	glColor4f(color.r, color.g, color.b, 1.0f);
	drawUnitCircle(GL_LINE_LOOP);
}

void BasicDrawObjects::DrawSegment(const Vector2f& p1, const Vector2f& p2, const Color3f& color)
{
    GLfloat vertices[2 * 2];
	
	vertices[0] = p1.x;
	vertices[1] = p1.y;
	vertices[2] = p2.x;
	vertices[3] = p2.y;
	glColor4f(color.r, color.g, color.b, 1.0f);
	glVertexPointer(2, GL_FLOAT, 0, vertices);
	glEnableClientState(GL_VERTEX_ARRAY);
	
	glDrawArrays(GL_LINES, 0, 2);
	
	glDisableClientState(GL_VERTEX_ARRAY);
}

void BasicDrawObjects::DrawPoint(const Vector2f& i_point, float i_size, const Color3f& i_color)
{
    glPointSize(i_size);
	glColor4f(i_color.r, i_color.g, i_color.b, 1.0f);
    
    GLfloat vertices[1 * 2];
	
	vertices[0] = i_point.x;
	vertices[1] = i_point.y;
	glVertexPointer(2, GL_FLOAT, 0, vertices);
	glEnableClientState(GL_VERTEX_ARRAY);
	
	glDrawArrays(GL_POINTS, 0, 1);
	
	glDisableClientState(GL_VERTEX_ARRAY);	
    
    glPointSize(1.0f);
}

void BasicDrawObjects::DrawRect(const Vector2f& i_min, const Vector2f& i_max, const Color4f& i_color)
{
    GLfloat vertices[4 * 2];
	
	vertices[0] = i_min.x;
	vertices[1] = i_min.y;
	vertices[2] = i_max.x;
	vertices[3] = i_min.y;
    vertices[4] = i_max.x;
	vertices[5] = i_max.y;
	vertices[6] = i_min.x;
	vertices[7] = i_max.y;
    
	glColor4f(i_color.r, i_color.g, i_color.b, i_color.a);
	glVertexPointer(2, GL_FLOAT, 0, vertices);
	glEnableClientState(GL_VERTEX_ARRAY);
	
	glDrawArrays(GL_LINE_LOOP, 0, 4);
	
	glDisableClientState(GL_VERTEX_ARRAY);
}

void BasicDrawObjects::DrawSolidRect(const Vector2f& i_min, const Vector2f& i_max, const Color4f& i_color)
{
    GLfloat vertices[4 * 2];
	
	vertices[0] = i_min.x;
	vertices[1] = i_min.y;
	vertices[2] = i_max.x;
	vertices[3] = i_min.y;
    vertices[4] = i_max.x;
	vertices[5] = i_max.y;
	vertices[6] = i_min.x;
	vertices[7] = i_max.y;
    
//    glColor4f(0.5f * i_color.r, 0.5f * i_color.g, 0.5f * i_color.b, 1.0f);
    
	glVertexPointer(2, GL_FLOAT, 0, vertices);
	glEnableClientState(GL_VERTEX_ARRAY);
	
    glEnable(GL_BLEND);
	glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glColor4f(i_color.r, i_color.g, i_color.b, i_color.a);
    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
	glDisable(GL_BLEND);
    	
    glColor4f(i_color.r, i_color.g,  i_color.b, i_color.a);
    glDrawArrays(GL_LINE_LOOP, 0, 4);
    
	glDisableClientState(GL_VERTEX_ARRAY);
}

void BasicDrawObjects::DrawTexturedRect(const Vector2f& i_min, const Vector2f& i_max, const Color4f& i_color, const Vector2f& i_uvMin, const Vector2f& i_uvMax)
{
    GLfloat vertices[4 * 2];
	GLfloat uvVertices[ 4 * 2];
    glAlphaFunc(GL_GREATER, 0.5f);
	
	vertices[0] = i_min.x;	vertices[1] = i_min.y;
	vertices[2] = i_max.x;	vertices[3] = i_min.y;
    vertices[4] = i_max.x;	vertices[5] = i_max.y;
	vertices[6] = i_min.x;	vertices[7] = i_max.y;

    uvVertices[0] = i_uvMin.x;	uvVertices[1] = i_uvMin.y;
	uvVertices[2] = i_uvMax.x;	uvVertices[3] = i_uvMin.y;
    uvVertices[4] = i_uvMax.x;	uvVertices[5] = i_uvMax.y;
	uvVertices[6] = i_uvMin.x;	uvVertices[7] = i_uvMax.y;
     
	glVertexPointer(2, GL_FLOAT, 0, vertices);
    glTexCoordPointer(2, GL_FLOAT, 0, uvVertices);
	glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
	
    glEnable(GL_BLEND);
	glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glColor4f(i_color.r, i_color.g, i_color.b, i_color.a);
    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
	glDisable(GL_BLEND);
    glAlphaFunc(GL_ALWAYS, 0.0f);
	
    
	glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}



STexLine BasicDrawObjects::CreateTexLine(const Vector2f& i_from, const Vector2f& i_to, float i_width)
{
    STexLine texLine;

    Vector2f vecTo = i_from - i_to;
    vecTo.Normalize();

    Vector2f perp = Perp(vecTo);
    
    texLine.m_LineQuadV[0] = i_from + perp * i_width;
    texLine.m_LineQuadV[1] = i_from - perp * i_width;
    texLine.m_LineQuadV[2] = i_to   - perp * i_width;
    texLine.m_LineQuadV[3] = i_to   + perp * i_width;
   
    
    texLine.m_LineQuadT[0] = Vector2f(0,0);
    texLine.m_LineQuadT[1] = Vector2f(0,1);
    texLine.m_LineQuadT[2] = Vector2f(1,1);
    texLine.m_LineQuadT[3] = Vector2f(1,0);
    
    return texLine;
}

void BasicDrawObjects::DrawTexturedLine(const Vector2f& i_from, const Vector2f& i_to, float i_width, const Color4f i_color)
{
    STexLine texLine = CreateTexLine(i_from, i_to, i_width);
    
    BasicDrawObjects::DrawTexturedPolygon((const Vector2f*)texLine.m_LineQuadV, (const Vector2f*)texLine.m_LineQuadT, 4, i_color);
}

// -----------------------------------------------------------------------------

